Skip to content

2.6. Workshop

In one glance

  • You will: Build eight small checkpoints and explain the behavior each one verifies.
  • You need: Step 1 completed; Python and SQLite familiarity. No API key is needed for checks.
  • Time: about 160 minutes, hands-on.

How does the workshop progress?

Each step copies your preceding source into a new learner-owned directory.

mise run lab -- list

Run workshop commands from the repository root. At each exercise below, run start N once, edit the created file, then run check N until it passes. If the directory already exists, continue editing it; a refused restart protects your work. All checks are offline. The learning/ directory is ignored by Git and survives runtime-state resets; copy or commit your work in your own repository for a durable backup.

start N carries your previous file forward and appends a scaffold for the step: each new function with its signature, a docstring, the page to read, and a body that raises NotImplementedError naming the missing behavior. A commented TOOLS = [...] line waits at the end, because attaching a tool to the agent is your decision, not the scaffold's. The first check fails until you replace every stub.

Check where you stand at any time:

mise run lab -- status

It marks each step passing, failing, or not started, then prints the one command that moves you forward. A failing check N ends with the page that owns the concept. mise run lab -- solution N prints the worked solution without changing your file. start N --reference starts from the preceding reference checkpoint when you deliberately join later. Starting an existing step always fails without overwriting it.

Your turn: can your tools retrieve only real incidents?

Implement list_open_incidents() and get_incident(incident_id) and attach them to your agent.

  • Mode: capstone carry-forward
  • Goal: Return only open rows and report missing incident IDs without inventing data.
  • Files to touch: learning/step-2/learner_agent/agent.py.
  • Preflight: Run mise run lab -- start 2 and mise run lab -- check 2. Predict the result for INC-999 and an SQL-like string. Read 3.1. Tools and inspect the seed schema; open SQLite with mode=ro.
  • Gate that proves completion: mise run lab -- check 2 returns exactly INC-002, INC-005, and INC-010, rejects unknown IDs, and accepts no invented evidence.
  • Final state: Keep the tools and compare with mise run lab -- solution 2. Use mise run lab -- run 2 only when you choose to spend model quota.

Your turn: can two conversations keep separate state?

Implement remember_incident(incident_id, tool_context) using ADK's conversation state.

  • Mode: capstone carry-forward
  • Goal: Remember a valid incident without leaking it to another conversation.
  • Files to touch: learning/step-3/learner_agent/agent.py.
  • Preflight: Run mise run lab -- start 3. Predict whether an unknown ID should replace a valid remembered ID. Read 2.4. Sessions.
  • Gate that proves completion: mise run lab -- check 3 verifies isolated state and rejects the invalid replacement.
  • Final state: Keep the new function and include it in the agent's tool list. Compare with mise run lab -- solution 3 after making your own attempt.

Your turn: can you prevent an unapproved action?

Implement propose_restart(service, tool_context) as a simulated action with explicit approval.

  • Mode: capstone carry-forward
  • Goal: Validate the service, request confirmation, require a rationale, and avoid repeating an approved action.
  • Files to touch: learning/step-4/learner_agent/agent.py.
  • Preflight: Run mise run lab -- start 4. Predict the state after denied, incomplete, and replayed approvals. Read the confirmation section of 3.1. Tools.
  • Gate that proves completion: mise run lab -- check 4 verifies no effect before approval, denial behavior, required rationale, and one recorded simulated effect after replay.
  • Final state: Keep the guarded function. This exercise stores synthetic state only; the completed reference adds transactional audit and crash recovery before deployment.

Your turn: can you bound the investigation workflow?

Implement build_workflow(model) with an investigation stage followed by a recommendation stage.

  • Mode: capstone carry-forward
  • Goal: Use a two-stage ADK Workflow named triage_workflow; share evidence while excluding write tools.
  • Files to touch: learning/step-5/learner_agent/agent.py.
  • Preflight: Run mise run lab -- start 5. Predict whether a recommendation stage needs restart authority. Read 3.5. Workflows.
  • Gate that proves completion: mise run lab -- check 5 verifies the investigate → recommend structure and excludes the restart tool from both stages. These are structural checks, not live reasoning-quality measurements.
  • Final state: Keep the workflow. mise run lab -- run 5 --workflow opens this composition in ADK Web and consumes quota when you send a message. Compare this small sequence with the reference's richer plan → investigate → evidence review → recommend graph.

Your turn: can a grader detect missing and invented evidence?

Implement grade_answer(answer, expected_ids) to compare incident IDs rather than wording.

  • Mode: capstone carry-forward
  • Goal: Reject answers that omit an expected ID or add an invented one.
  • Files to touch: learning/step-6/learner_agent/agent.py.
  • Preflight: Run mise run lab -- start 6. Predict each label in agents/python/labs/cases.json before running the grader. Read 4.4. Evaluations.
  • Gate that proves completion: mise run lab -- check 6 agrees with all recorded labels, including false-positive and missing-evidence cases.
  • Final state: Keep your grader and its cases. Record the result with MLflow when the evaluation lesson introduces it; grade new held-out cases before making a quality claim.

Your turn: can retrieved text stay data?

Implement neutralize(text) and read_runbook(slug) so a runbook reaches the model fenced as data, with injected instructions removed.

  • Mode: capstone carry-forward
  • Goal: Reject a traversal slug before any file access, fence runbook text between DATA_START and DATA_END, and remove instruction-like phrases without touching benign evidence.
  • Files to touch: learning/step-7/learner_agent/agent.py.
  • Preflight: Run mise run lab -- start 7. Predict each label in agents/python/labs/injections.json before running the check. Two cases try to slip past a naive filter: fullwidth letters, and a line that closes your fence early. Read 4.5. Guardrails.
  • Gate that proves completion: mise run lab -- check 7 flags all five attacks, leaves all four benign lines byte-identical, and refuses ../../.env.
  • Final state: Keep both functions and attach read_runbook to TOOLS. Then read agents/data/runbooks/cascade-failure.md through your tool: it quotes an attack as a warning, and your filter neutralizes the quote too. A pattern list is a tripwire, not a parser; fencing, least privilege, and human approval are the defenses that do not depend on wording.

Your turn: can you share read tools without sharing authority?

Implement build_mcp_server() so another agent can call your three read tools, but never propose_restart.

  • Mode: capstone carry-forward
  • Goal: Return an MCP SDK 2.x MCPServer exposing exactly list_open_incidents, get_incident, and read_runbook, each annotated read-only.
  • Files to touch: learning/step-8/learner_agent/agent.py.
  • Preflight: Run mise run lab -- start 8. Predict why remember_incident and propose_restart stay off the server even though both are useful. Read 3.3. MCP.
  • Gate that proves completion: mise run lab -- check 8 connects a real MCP client in process, lists exactly the three read tools, checks their read-only annotations, and calls get_incident for a known and an unknown ID.
  • Final state: Keep the server factory. The in-process client speaks MCP revision 2026-07-28 with no network. 5.2. MCP Gateway later puts the reference server behind a gateway allowlist, the platform version of the same boundary.

What proves this page worked?

mise run lab -- status
mise run lab -- check 8

You are done when:

  • status marks all eight steps passing, and you can explain the failure each check catches.
  • You can distinguish a Python behavior check, workflow structure check, grader calibration, guardrail regression, and live model evaluation.
  • You can name one attack your step 7 filter would miss, and the control that still contains it.
  • Your work is preserved and you know where each worked solution lives.

Continue to 4.8. Developer Handoff after consulting the capability and quality pages needed for your exercises.